package com.sinooceanland;

import android.Manifest;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.media.audiofx.Visualizer;
import android.os.Environment;
import android.widget.Toast;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.yanzhenjie.permission.Action;
import com.yanzhenjie.permission.AndPermission;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class RNRecorderModule extends ReactContextBaseJavaModule {

    private static final String TAG = "RNRecorderModule";
    private final ReactApplicationContext reactContext;
    Timer recorderTimer;
    Timer playingTimer;
    Timer amplitudeTimer;
    private MediaRecorder mRecorder = null;
    private String mFileName = null;//文件名
    private String mFilePath = null;//文件路径
    private MediaPlayer mMediaPlayer = null;
    private int recordLength = 0;
    private int playLength = 0;
    private int BASE = 600;//计算录音音量的参考值

    private AudioManager mAudioManager = null;
    private int mRecorderMaxDuration = 60000;

    private Visualizer mVisualizer = null;

    private long mStartTimeMillis = 0;

    private List<String> mList;//用于处理多段录音合并
    private boolean isPause = false;//用来标识录音过程是否暂停过，默认为未暂停
    private boolean isRecording = false;//用来标识是否正在录音
    private final String SUFFIX = ".amr";

    private File myRecAudioDir;
    private File mFile;

    private File parentFile;

    public RNRecorderModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
        mAudioManager = (AudioManager) this.reactContext.getSystemService(Context.AUDIO_SERVICE);
        mList = new ArrayList<>();
    }

    @Override
    public String getName() {
        return "RNRecorder";
    }


    /**
     * 播放计时器
     */
    private void startPlayingTimer() {
        playingTimer = new Timer();
        playingTimer.schedule(new TimerTask() {
            public void run() {
                if (playLength > mMediaPlayer.getDuration()) {
                    stopPlaying();
                } else {
                    WritableMap body = Arguments.createMap();
                    body.putInt("playingRealTime", playLength);
                    body.putInt("playingRestTime", mMediaPlayer.getDuration() - playLength);
                    body.putInt("duration", mMediaPlayer.getDuration());
                    body.putBoolean("isPlay", true);
                    sendEvent("playingProgress", body);
                    playLength += 1000;
                }
            }
        }, 0, 1000);

    }

    /**
     * 获取当前播放音频频谱
     */
    private void getVisualizer() {
        if (mMediaPlayer != null) {
            mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
            mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[0]);//采样值128
            mVisualizer.setDataCaptureListener(
                    new Visualizer.OnDataCaptureListener() {

                        @Override
                        public void onWaveFormDataCapture(Visualizer visualizer,
                                                          byte[] waveform, int samplingRate) {

                        }

                        @Override
                        public void onFftDataCapture(Visualizer visualizer,
                                                     byte[] fft, int samplingRate) {
                            byte[] model = new byte[fft.length / 2 + 1];
                            model[0] = (byte) Math.abs(fft[1]);
                            int j = 1;

                            for (int i = 2; i < fft.length; ) {
                                model[j] = (byte) Math.hypot(fft[i], fft[i + 1]);
                                i += 2;
                                j++;
                            }


                            WritableArray array = Arguments.createArray();
                            for (byte x : model) {
                                array.pushInt(x);
                            }
                            WritableMap map = Arguments.createMap();
                            map.putArray("spectrum", array);
                            sendEvent("spectrumProgress", map);
                        }
                    }, Visualizer.getMaxCaptureRate() / 2, false, true);

            mVisualizer.setEnabled(true);
        } else {
            // Log.e(TAG, "can not find any audio");
        }
    }

    /**
     * 暂停播放
     */
    @ReactMethod
    private void pausePlaying() {
        if (playingTimer != null) {
            playingTimer.cancel();// 停止定时器
        }
        if (mVisualizer != null) {
            mVisualizer.setEnabled(false);
        }

        if (mMediaPlayer != null) {
            mMediaPlayer.pause();
        }
    }

    /**
     * 恢复播放
     */
    @ReactMethod
    private void resumePlaying() {
        mMediaPlayer.start();
        getVisualizer();
        startPlayingTimer();
    }

    /**
     * 从指定时间开始播放网络音频
     *
     * @param url
     * @param second
     */
    @ReactMethod
    private void startPlaying(final String url, final Integer second) {
        AndPermission.with(getReactApplicationContext())
                .permission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO)
                .onGranted(new Action() {
                    @Override
                    public void onAction(List<String> permissions) {

                        mMediaPlayer = new MediaPlayer();
                        try {
                            if (url != null) {
                                mMediaPlayer.setDataSource(url);//播放网络录音
                            } else {
                                mMediaPlayer.setDataSource(mFile.getAbsolutePath());//播放本地录音
                            }
                            mMediaPlayer.prepare();
                            if (second != null) {//从指定时间开始播放
                                int seekToTime = 0;
                                if (second < 0) {
                                    seekToTime = 0;
                                } else if (second > mMediaPlayer.getDuration()) {
                                    seekToTime = mMediaPlayer.getDuration();
                                } else {
                                    seekToTime = second * 1000;
                                }
                                playLength = seekToTime;
                                mMediaPlayer.seekTo(seekToTime);
                                mMediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
                                    @Override
                                    public void onSeekComplete(MediaPlayer mp) {
                                        toPlay();
                                    }
                                });
                            } else {//默认从开始时间开始播放
                                mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                                    @Override
                                    public void onPrepared(MediaPlayer mp) {
                                        toPlay();
                                    }
                                });
                            }


                        } catch (IOException e) {

                        }
                    }
                })
                .onDenied(new Action() {
                    @Override
                    public void onAction(List<String> permissions) {
                        for (int i = 0; i < permissions.size(); i++) {
                            // Log.e(TAG, "拒绝了权限：" + permissions.get(i));
                        }
                    }
                })
                .start();
    }

    /**
     * 播放方法
     */
    private void toPlay() {
        mMediaPlayer.start();
        getVisualizer();
        startPlayingTimer();
    }
    
    /**
     * 停止录音
     */
    @ReactMethod
    private void stopPlaying() {
        try {
            if (mMediaPlayer != null) {
                playingTimer.cancel();// 停止定时器
                mVisualizer.setEnabled(false);
                mVisualizer.release();
                WritableMap body = Arguments.createMap();
                body.putInt("playingRealTime", playLength);
                body.putInt("playingRestTime", (mMediaPlayer.getDuration() - playLength) < 0 ? 0 : mMediaPlayer.getDuration() - playLength);
                body.putInt("duration", mMediaPlayer.getDuration());
                body.putBoolean("isPlay", false);
                sendEvent("playingProgress", body);
                mMediaPlayer.stop();
                mMediaPlayer.reset();
                mMediaPlayer.release();
                mMediaPlayer = null;
                playLength = 0;
            }
        } catch (Exception e) {
            // Log.e(TAG, "stop play() failed");
        }
    }

    /**
     * 扬声器与听筒切换
     *
     * @param isSpeakerphoneOn
     * @param promise
     */
    @ReactMethod
    public void setSpeakerphoneOn(Boolean isSpeakerphoneOn, Promise promise) {
        try {
            mAudioManager.setSpeakerphoneOn(isSpeakerphoneOn);
            if (!isSpeakerphoneOn) {
                mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
            }
            WritableMap map = Arguments.createMap();
            map.putBoolean("isSuccess", true);
            promise.resolve(map);

        } catch (Exception e) {
            promise.reject(e);
        }
    }

    /**
     * 当前是喇叭播放还是听筒播放
     *
     * @param promise
     */
    @ReactMethod
    private void isSpeakerphoneOn(Promise promise) {
        try {
            promise.resolve(mAudioManager.isSpeakerphoneOn());
        } catch (Exception e) {
            promise.reject(e);
        }
    }


    /**
     * 录音文件路径
     */
    private void setFileNameAndPath() {
        try {
            mFileName = "My Recording_" + System.currentTimeMillis() + ".mp3";
            mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath();
            parentFile = new File(mFilePath + "/SoundRecorder");
            if (!parentFile.exists()) {
                parentFile.mkdirs();
            }
            mFilePath += "/SoundRecorder/" + mFileName;


        } catch (Exception e) {
            // Log.e(TAG, "build directory() failed");
        }
    }

    /**
     * 开始录音
     *
     * @param second
     */
    @ReactMethod
    private void startRecording(int second) {
        if (handleRecorderDuration(second)) {
            AndPermission.with(getReactApplicationContext())
                    .permission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO)
                    .onGranted(new Action() {
                        @Override
                        public void onAction(List<String> permissions) {
                            try {
                                setFileNameAndPath();
                                isRecording = true;
                                mRecorder = new MediaRecorder();
                                mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置麦克风
                                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
                                mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
                                mRecorder.setOutputFile(mFilePath);
                                mRecorder.setAudioChannels(1);//声道
                                mRecorder.setAudioEncodingBitRate(192000);//比特率
//                                mRecorder.setMaxDuration(mRecorderMaxDuration);//最大录音时长
                                try {
                                    mRecorder.prepare();
                                    mRecorder.start();
                                    mStartTimeMillis = System.currentTimeMillis();
                                    getAmplitude();
                                    startRecordingTimer();
                                } catch (IOException e) {
                                    // Log.e(TAG, "prepare() failed");
                                }
                            } catch (Exception ex) {
                                ex.printStackTrace();
                            }
                        }
                    })
                    .onDenied(new Action() {
                        @Override
                        public void onAction(List<String> permissions) {
                            for (int i = 0; i < permissions.size(); i++) {
                                // Log.e(TAG, "拒绝了权限：" + permissions.get(i));
                            }
                        }
                    })
                    .start();
        } else {
            WritableMap body = Arguments.createMap();
            body.putInt("recordingRealTime", 0);
            body.putInt("recordingRestTime", 0);
            body.putBoolean("isRecord", false);
            body.putString("msg", "录音时间不能少于5秒");
            body.putString("filePath", "");
            sendEvent("recordingProgress", body);
        }


    }

    @ReactMethod
    public void pauseRecording() {
        //正在录音，点击暂停
        mList.add(mFilePath);
        isRecording = false;
        isPause = true;//只有一执行暂停函数，设为暂停状态
        amplitudeTimer.cancel();
        if (mRecorder != null) {
            mRecorder.stop();
            mRecorder.release();
            mRecorder = null;
        }
        WritableMap body = Arguments.createMap();
        body.putInt("recordingRealTime", recordLength);
        body.putInt("recordingRestTime", (mRecorderMaxDuration - recordLength));
        body.putString("msg", "暂停录音");
        body.putBoolean("isRecord", false);
        body.putString("filePath", "");
        sendEvent("recordingProgress", body);
        stopRecorderTimer();

    }

    private void showToast(String msg) {
        Toast.makeText(this.reactContext, msg, Toast.LENGTH_LONG).show();
    }

    private void getInputCollection(List list, boolean isAddLastRecord) {
        String mMinute1 = System.currentTimeMillis() + "";
        String pathStr = Environment.getExternalStorageDirectory().getPath() + "/YYT";
        myRecAudioDir = new File(pathStr);
        if (!myRecAudioDir.exists()) {
            myRecAudioDir.mkdirs();
        }
        // 创建音频文件,合并的文件放这里
        File file1 = new File(myRecAudioDir, mMinute1 + SUFFIX);
        FileOutputStream fileOutputStream = null;
        if (!file1.exists()) {
            try {
                file1.createNewFile();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        try {
            fileOutputStream = new FileOutputStream(file1);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //list里面为暂停录音 所产生的 几段录音文件的名字，中间几段文件的减去前面的6个字节头文件
        for (int i = 0; i < list.size(); i++) {
            File file = new File((String) list.get(i));
            try {
                FileInputStream fileInputStream = new FileInputStream(file);
                byte[] myByte = new byte[fileInputStream.available()];
                int length = myByte.length; //文件长度
                if (i == 0) {//头文件
                    while (fileInputStream.read(myByte) != -1) {
                        fileOutputStream.write(myByte, 0, length);
                    }
                } else {//之后的文件，去掉头文件就可以了
                    while (fileInputStream.read(myByte) != -1) {
                        fileOutputStream.write(myByte, 6, length - 6);
                    }
                }
                fileOutputStream.flush();
                fileInputStream.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        //结束后关闭流
        try {
            fileOutputStream.close();
            mFile = file1;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //合成一个文件后，删除之前暂停录音所保存的零碎合成文件
        deleteListRecord(isAddLastRecord);

    }


    private void deleteListRecord(boolean isAddLastRecord) {
//        for (int i = 0; i < mList.size(); i++) {
//            File file = new File((String) mList.get(i));
//            if (file.exists()) {
//                file.delete();
//            }
//        }
        mList = new ArrayList<>();
        //正在暂停后，继续录音的这一段音频文件
//        if (isAddLastRecord) {
        parentFile.delete();
//        }
    }


    /**
     * 停止录音
     */
    @ReactMethod
    public void stopRecording() {
        if (isRecording) {
            mList.add(mFilePath);
        }
        getInputCollection(mList, true);
        if (mRecorder != null) {
            mRecorder.stop();
            mRecorder.release();
            mRecorder = null;
        }
        stopRecorderTimer();
        amplitudeTimer.cancel();
        recordLength = 0;
        isRecording = false;
        WritableMap body = Arguments.createMap();
        body.putInt("recordingRealTime", (int) (System.currentTimeMillis() - mStartTimeMillis));
        body.putInt("recordingRestTime", (mRecorderMaxDuration - recordLength) < 0 ? 0 : mRecorderMaxDuration - recordLength);
        body.putString("msg", "录音结束");
        body.putBoolean("isRecord", false);
        body.putString("filePath", mFile.getAbsolutePath());
        sendEvent("recordingProgress", body);
    }

    /**
     * 录音计时器
     */
    private void startRecordingTimer() {
        recorderTimer = new Timer();
        recorderTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                if (recordLength >= mRecorderMaxDuration) {
                    stopRecording();
                } else {
                    WritableMap body = Arguments.createMap();
                    body.putInt("recordingRealTime", recordLength);
                    body.putInt("recordingRestTime", (mRecorderMaxDuration - recordLength));
                    body.putString("msg", "正在录音…");
                    body.putBoolean("isRecord", true);
                    body.putString("filePath", "");
                    sendEvent("recordingProgress", body);
                    recordLength += 1000;
                }
            }

        }, 0, 1000);
    }


    private void stopRecorderTimer() {
        if (recorderTimer != null) {
            recorderTimer.cancel();
        }
    }


    /**
     * 获取录音的分贝
     *
     * @return
     */
    private int recorderVolume() {
        int volume = 0;
        int ratio;
        ratio = mRecorder.getMaxAmplitude() / BASE;
        if (ratio > 1) {
            volume = (int) (20 * Math.log10(ratio));
        }
        return volume;
    }


    /**
     * 发送监听
     *
     * @param eventName
     * @param params
     */
    private void sendEvent(String eventName, Object params) {
        getReactApplicationContext()
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(eventName, params);
    }

    /**
     * 处理录音时长
     *
     * @param second
     * @return
     */
    private boolean handleRecorderDuration(int second) {
        boolean isSuccess;
        if (second >= 5) {
            mRecorderMaxDuration = second * 1000;
            isSuccess = true;
        } else {
            isSuccess = false;
        }
        return isSuccess;
    }

    /**
     * 获取录音分贝
     */
    private void getAmplitude() {
        amplitudeTimer = new Timer();
        amplitudeTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                WritableMap body = Arguments.createMap();
                body.putInt("amplitude", recorderVolume());
                sendEvent("amplitudeProgress", body);
            }
        }, 0, 100);

    }


    /**
     * 设置录音时长
     *
     * @param second
     * @param promise
     */
    @ReactMethod
    private void setRecorderMaxDuration(int second, Promise promise) {
        try {
            WritableMap map = Arguments.createMap();
            if (second < 5) {
                map.putString("msg", "设置录音时间太短");
                map.putBoolean("isSuccess", false);
            } else {
                mRecorderMaxDuration = second * 1000;
                map.putBoolean("isSuccess", true);
            }
            promise.resolve(map);
        } catch (Exception e) {
            promise.reject(e);
        }
    }

}
